File: PDR1.ZIP Author: Patrick Reilly (Compuserve 71333,2764) Release: v0.9 2/28/95 This file contains a C library of functions for accessing the DPMI version 0.9 API. For implementation, I've written all the source files in assembly. I used TASM and TASM32, version 4.0 to build these. I've included two files to make these libraries (MAKEFILE.16 and MAKEFILE.32), which I ran with MAKE version 3.7. Contents: this .zip file contains a multitude of .asm files (one for each C function represented), DPMI.H, and the make files. The .asm files are split up in this fashion so that when you link with the built DPMIC16.lib or DPMIC32.LIB, you will only link the actual functions you need (and not one big module that you might only be using a small percentage of). I wrote and compiled this library with BC++4.5, TASM/32 4.0, and MAKE3.7. I haven't had a chance to debug all of it, so if you run into problems leave me a note and I'll try to fix it. However, I do not provide design and use support for this library; if you have DPMI questions, you should address them to the BCPPDOS forum, the DPMI section (7). This library is provided as is, and I am not responsible for your usage nor for any problems you encounter with it. It is provided into the public domain - that is, it's "freeware". I wrote this library following the DPMI 0.9 specs as published by Intel (r) dated July 26, 1990. A friend obtained a copy of this document for me off the internet, so I'm not sure where it's available. You can try the INTELFORUM on compuserve, or browse the net. The text file name is DPMISPEC.TXT, although I would assume that in electronic form it is zipped up. This file was zipped up using PKZIP version 2.04g. PKZIP is a registered trademark of PKWARE. The Library DPMI.H This header file defines the types and function prototypes for the library. The following are the types defined: ---------------------------------------------------------------------------- typedef DPMIFAR For DPMI16, this expands to the __far keyword. For DPMI32, it expands to nothing. struct tagPMRegs typedef PMRegs typedef LPPMRegs PMRegs defines a data structure that encapsulates the 80x86 register set in a format directly accessible to the DPMI 0.9 translation services. PMRegs is actually made up of a union of the three structures PMByteRegs, PMWordRegs and PMDWordRegs, which allow access to the 8-bit registers, 16-bit registers and 32-bit registers respectively. The PMByteRegs member is named h, the PMWordRegs member is named w, and the PMDwordRegs registers is named x. So to access an 8-bit register (say, the AL registers) from a PMRegs variable obj, you would use obj.h.al = 3. For a 16-bit register (say AX), you would use obj.w.ax = 3; for a 32-bit (say EAX), you would use obj.x.eax = 3. The following members are common to all three structures: flags, es, ds, fs, gs, ip, cs, sp, ss. This means that you could access the ES representation, say, via either obj.h.es, obj.w.es, or obj.x.es. You might wonder why ESP and EIP are not represented in this structure (or usable in the DPMI 0.9 translation functions that use PMRegs). This is because the translation functions are used to access real mode functions - which operate in the 1MB real mode memory space, and use a 16-bit IP and stack. As in Windows notation, LPPMRegs is a (far) pointer to a PMRegs object. typedef PMSelector typedef RMSegment These two 16-bit types represent a selector (only used in protected mode) and a segment (only used in real mode). You could easily do without these simple typedefs (use unsigned short instead), but they allow your code to look cleaner, since at a glance you can tell whether an object can be used with protected or real mode. typedef LinearAddress This 32-bit type represents a linear memory address. By linear, this means that for any two LinearAddress objects x, y=x+1, the memory referenced by 'y' is exactly one byte above the memory referenced by 'x'. In other words, this is NOT a combination of a segment:offset pair as is used in real mode memory referencing. typedef PMHandle This 32-bit type represents a handle used by some DPMI linear memory functions. typedef RMAddress define RM_SEGMENT define RM_OFFSET This 32-bit type represents a RMSegment:offset pair, where the high word is the RMSegment, and the low word is the offset. Note that this is NOT the same as a LinearAddress type! If you were using windows.h and wanted to convert a RMAddress to a LinearAddress, you would use: RMAddress rmaddr = ...; LinearAddress addr = (((LinearAddress)HIWORD(rmaddr)) << 4) + LOWORD(rmaddr); Note that a RMAddress can only reference up to (1MB+64KB-1), whereas a LinearAddress can reference up to the full 32-bit memory range. Included are two macros to extract the RMSegment and offset from a RMAddress: RM_SEGMENT(x) will evaluate to a RMSegment, and is the segment of x. RM_OFFSET(x) will evaluate to an unsigned short and is the offset of x. struct tagDPMIVersion typedef DPMIVersion typedef LPDPMIVersion enum version_flags This is version information for the DPMI host. Members are: major 8-bit Major version number (ie 0x01 == version 1.xx) minor 8-bit Minor version number (ie 0x09 == version x.09) flags 16-bit See version_flags enum below cpu 8-bit CPU version (0x02 = 80286, 0x03 = 80386, etc) masterPic 8-bit Virtual master PIC state. slavePIC 8-bit Virtual slave PIC state. The version_flags enumeration lists flags that can be or'd with DPMIVersion flags to boolean flag states. These flags are: isDPMI32 Non-zero if DPMI32 is the host. hasRealModeInterrupts Non-zero if real mode interrupts (or V86 mode) are used. hasVirtualMemory Non-zero if virtual memory is supported. LPDPMIVersion types a (far) pointer to a DPMIVersion object. struct tagDPMIMemInfo typedef DPMIMemInfo typedef LPDPMIMemInfo This is the memory information for the DPMI host. Members are: maxFreeBlocks Largest available free block in bytes. maxUnlockedPage Maximum unlocked page allocation. maxLockedPage Maximum locked page allocation. linearPages Linear address space size in pages. totalUnlockedPages Total number of unlocked pages. totalFreePages Number of free pages. totalPhysicalPages Total number of physical pages. freeLinearPages Free linear address space in pages. partitionSize Size of paging file/partition in pages. reserved[] Unused. struct tagDPMIInfo typedef DPMIInfo typedef LPDPMIInfo This is the DPMI host information. Members are: supports32Bit Non-zero if the host supports DPMI32. cpu See the same entry under DPMIVersion. major See the same entry under DPMIVersion. minor See the same entry under DPMIVersion. typedef PMRights enum pmrights_types This 16-bit type represents the access rights for a PMSelector. It is really a bit array, whose members are accessed via the pmrights_types enumerations. They are: rights_Accessed rights_ReadWrite rights_Conforming rights_Code rights_Reserved1 (not used by user) rights_Level (2-bits) rights_Present rights32 (mask for all DPMI32 rights bits) rights32_Reserved2 (32-bit; not used by user) rights32_Avl (32-bit) rights32_Reserved3 (32-bit; not used by user) rights32_Default32 (32-bit) rights32_PageGranular (32-bit) typedef Descriptor typedef LPDescriptor typedef LPCDescriptor This type (an 8-byte character array) represents a protected mode descriptor. PMFarAddress This type represents a far protected mode pointer. In DPMI16, it is just a void __far*. However, in DPMI32, it is a structure representing a 48-bit pointer. In DPMI32, the first 32-bits of this structure are the offset of the pointer, and the last 16-bits are the selector. typedef DosMemory typedef LPDosMemory define DM_SEGMENT define DM_SELECTOR This 32-bit type represents a bit-packed structure of a PMSelector and a RMSegment (returned by dpmi_allocateDosMem() function). Two macros are provided to extract the members: DM_SEGMENT(x) evaluates to the RMSegment of the object. DM_SELECTOR(x) evaluates to the PMSelector of the object. typedef WatchPoint enum watchpoint_types This 16-bit type represents a watch point "handle". The watchpoint_types enumeration represents flags used with the watch point functions. ---------------------------------------------------------------------------- The following are descriptions of the function groups, and the prototypes for the functions: Mode Detection -------------- These functions are used to determine if a DPMI host is present, and if the CPU is currently running in protected mode. Note that ALL functions except dpmi_present() assume that a DPMI host IS available; if one is not available, the functions can crash. int DPMIFAR dpmi_present( LPDPMIInfo info ); Returns 0 if a DPMI host was not detected, else returns 1. If info is non-null, then info will be filled with the host information. int DPMIFAR dpmi_running(void); Returns 0 if the CPU is in real mode, else 1 if in protected mode. LDT Descriptor Management Services ---------------------------------- These functions allow you to allocate, free, and manipulate protected mode selectors and descriptors. PMSelector DPMIFAR dpmi_allocateSelector( unsigned short count ); Tries to allocate congruent selectors. On success, returns the first of the allocated selectors; on failure, returns 0. The selectors have no limit or size, although they do have "standard" data rights. You can use dpmi_setSelectorLinearAddress() and dpmi_setSelectorLimit() to give the selectors a size and limit. If is greater than one, then the selectors are congruent; you can calculate the following selector by calling dpmi_getSelectorInc() and adding the returned value to a selector. For example: PMSelector first, second; unsigned short inc; first = dpmi_allocateSelector(2); inc = dpmi_getSelectorInc(); second = first+inc; ... Use dpmi_freeSelector() to free selectors allocated with this function. If you allocate more than one selector (count > 1), then you ONLY free the selector returned by this function (you do NOT free any of the other selectors in the array!). Remember that there are normally only 8192 selectors available for allocation! int DPMIFAR dpmi_freeSelector( PMSelector sel ); Frees a selector (or congruent array of selectors). Returns 1 on success, or 0 on failure. Use this function to free selectors allocated with dpmi_allocateSelector(), dpmi_aliasCodeToData(), or dpmi_allocateSpecificSelector(). PMSelector DPMIFAR dpmi_segmentToSelector( RMSegment seg ); Returns a selector for a particular real mode segment address. Returns the selector on success, or 0 on failure. Note that these selectors are limited resources, and that you must NOT free, or modify, the returned selector. The selector will have a linear base address corresponding to :0000h real mode memory, and a limit of 64KB. If you call this function more than once with the same value, then the same selector will be returned. For example: if you want to access the video memory at real mode address A000:0000 you could use: PMSelector sel = dpmi_segmentToSelector( 0xA000U ); char* buffer = (char*) malloc(64000U); // buffer is a work buffer for a 320x200x256 virtual screen. ... // fill in buffer // Now copy the buffer to video memory. #ifdef __FLAT__ copy32aux( 0, sel, (unsigned long)buffer, _DS, 64000L ); #else _fmemcpy( MK_FP(sel,0), buffer, 64000U ); #endif ... unsigned short DPMIFAR dpmi_getSelectorInc(void); Returns a value that can be added to a selector to access it's next congruent selector. Usually used with the selector returned by dpmi_allocateSelector() to calculate subsequent congruent selectors. LinearAddress DPMIFAR dpmi_getSelectorLinearAddress( PMSelector sel ); On success, returns the linear base address for a selector; on failure returns 0. int DPMIFAR dpmi_setSelectorLinearAddress( PMSelector sel, LinearAddress addr ); Use this function to set the linear base address for a selector. On success returns 1; on failure returns 0. unsigned long DPMIFAR dpmi_getSelectorLimit( PMSelector sel ); Returns the limit for a selector on success, else 0 on failure. int DPMIFAR dpmi_setSelectorLimit( PMSelector sel, unsigned long len ); Use this function to set the limit for a selector. On success returns 1; on failure returns 0. PMRights DPMIFAR dpmi_getSelectorRights( PMSelector sel ); Returns the access rights for a selector on success, else 0 on failure. int DPMIFAR dpmi_setSelectorRights( PMSelector sel, PMRights rights ); Use this function to set the access rights for a selector. Returns 1 on success, or 0 on failure. PMSelector DPMIFAR dpmi_aliasCodeToData( PMSelector codeSel ); Use this function to allocate a selector that has "normal" data access rights, but the same base linear address and limit of the given code selector. Returns the selector on success, or 0 on failure. Use dpmi_freeSelector() to free the selector when you're done with it. int DPMIFAR dpmi_getDescriptor( PMSelector sel, LPDescriptor buf ); Use this function to get the descriptor for a selector. Returns 1 on success, or 0 on failure. int DPMIFAR dpmi_setDescriptor( PMSelector sel, LPCDescriptor buf ); Use this function to set the descriptor for a selector. Returns 1 on success, or 0 on failure. int DPMIFAR dpmi_allocateSpecificSelector( PMSelector sel ); Use this function to allocate a specific selector for which you already know the value. Returns 1 on success, or 0 on failure. Use dpmi_freeSelector() to free the selector when you're done with it. DOS Memory Management Services ------------------------------ These functions are used to allocate, reallocate, or free memory accessible in the DOS real mode memory range (0-640KB). Since this memory is accessible to both real and protected mode code, they are useful for interprocess buffers. DosMemory DPMIFAR dpmi_allocateDosMem( unsigned long len ); Allocate dos memory of bytes. Returns a DosMemory object (containing both a RMSegment and a PMSelector) on success, or 0 on failure. Example: typedef struct tagECB {...} ECB; // Used for Netware functions. DosMemory mem; PMSelector sel; ECB DPMIFAR* ecbPtr; mem = dpmi_allocateDosMem( sizeof(ECB) ); sel = DM_SELECTOR(mem); #ifdef __FLAT__ ecbPtr.offset = 0; ecbPtr.selector = sel; ... #else ecbPtr = (ECB DPMIFAR*) MK_FP(sel, 0); ... #endif // You now have a ECB pointer that can be used with the real mode Netware // functions! For Netware, use the real mode address of the memory; for // example: // RMAddress addr; // addr.offset = 0; // addr.segment = DM_SEGMENT(mem); // ... // In your protected mode program, juse access it with ecbPtr. When you're done with this dos memory, use dpmi_freeDosMem() to free it. For example: ... dpmi_freeDosMem( DM_SELECTOR(mem) ); ... Note that for both the segment and the selector, the offset to this buffer is 0. int DPMIFAR dpmi_freeDosMem( PMSelector sel ); Use this function to free memory allocated with dpmi_allocateDosMem(). Returns 1 on success, or 0 on failure. int DPMIFAR dpmi_reallocateDosMem( PMSelector sel, unsigned long len ); Use this function to reallocate dos memory that was allocated with the function dpmi_allocateDosMem(). Returns 1 on success, or 0 on failure. Interrupt Services ------------------ These functions are used to get and set vectors for real mode interrupts, protected mode interrupts, and protected mode exceptions. RMAddress DPMIFAR dpmi_getRMVect( unsigned char intNo ); Use this function to get the real mode address of a real mode interrupt vector. Returns the vector on success, or 0 on failure. int DPMIFAR dpmi_setRMVect( unsigned char intNo, RMAddress addr ); Use this function to set a real mode vector for a real mode interrupt. Returns 1 on success, or 0 on failure. PMFarAddress DPMIFAR dpmi_getPMVect( unsigned char intNo ); Use this function to get the protected mode address of a protected mode interrupt vector. Returns the vector on success, or 0 on failure. Note that with DPMI32, you are returning a struct - the implementation for doing this varies between compiler manufacturers (this code is for BC++ 4.5). int DPMIFAR dpmi_setPMVect( unsigned char intNo, PMFarAddress addr ); Use this function to set the protected mode address of a protected mode interrupt vector. Returns 1 on success, or 0 on failure. PMFarAddress DPMIFAR dpmi_getPMHandler( unsigned char faultNo ); Use this function to get the address of an exception handler. Returns the address on success, or 0 on failure. Note that with DPMI32 you are returning a struct - the implementation for doing this varies between compiler manufacturers (this code is for BC++ 4.5). int DPMIFAR dpmi_setPMHandler( unsigned char faultNo, PMFarAddress addr ); Use this function to set the vector for an exception handler. Returns 1 on success, or 0 on failure. Translation Services -------------------- These functions allow you to interact with real mode procedures, and also retrieve DPMI host version information (to tell if something is supported). int DPMIFAR dpmi_intr( unsigned char intNo, LPPMRegs regs ); Use this function to call a real mode interrupt. should contain the desired values for the registers on entry to the interrupt. Returns 1 on success, or 0 on failure. If successful, will contain the values of the CPU registers when the interrupt returned. Note that the cs and ip members are ignored by this call, and that on return ss, sp, cs and ip are NOT the ones returned by the interrupt. If ss and sp are 0, then the DPMI host will provide a real mode stack, but this stack will only hold 30 words (60 bytes)! Note too that you will be entering real mode code. This means that the members that represent segment registers MUST contain RMSegment values, and not PMSelector values (if they are used by the interrupt). A good practice is to use dpmi_allocateDosMem() to allocate any buffers that the interrupt needs to access (and use DM_SEGMENT() to get the RMSegment for the buffer), and to set any unused segment registers to 0. For example: PMRegs regs; DosMemory mem; ... memset( ®s, 0, sizeof(PMRegs) ); // zero unused registers mem = dpmi_allocateDosMem( 1024 ); // we want a 1K stack! regs.h.ss = DP_SEGMENT(mem); regs.h.sp = 1020; // don't point at *bottom* of stack! ... dpmi_intr( 0x21, ®s ); dpmi_freeDosMem( DM_SELECTOR(mem) ); ... int DPMIFAR dpmi_callFar( RMAddress addr, LPPMRegs regs ); Use this function to call a real mode procedure. should contain the desired values for the registers on entry to the function, and the function MUST return with a RETF call (be a far function). For more information on , see dpmi_intr(). int DPMIFAR dpmi_callIntr( RMAddress addr, LPPMRegs regs ); This function is just like dpmi_callFar(), but the difference is that procedure you're calling returns with an IRET instruction instead of a RETF instruction. RMAddress DPMIFAR dpmi_allocateCallBack( PMFarAddress proc, LPPMRegs regs ); Use this function to allocate a "thunk" which real mode code can call to get to a protected mode procedure in . The thunk will save all the current (real mode) register values in , switch into protected mode, call , switch back to real mode, restore the registers from the values in , and return (with a RETF). This allows real mode code to call protected mode code, such as when you're registering a mouse handler callback, etc. isn't in a good form for a C function. On entry, has the following register values: DS:SI is the selector:offset of the real mode stack (DS:ESI in DPMI32). ES:DI is the selector:offset of (ES:EDI in DPMI32). SS:SP is a locked protected mode stack provided by the host (SS:ESP). All other registers are undefined. When returns it must: Return with an IRET call, not a RET or RETF! ES:(E)DI is the selector:offset of a PMRegs object You have to watch out for reentrance, since you've only got one object for this callback. If the callback takes a while, you'll want to copy the struct (in ES:(E)DI) to an allocated buffer and re-enable interrupts. int DPMIFAR dpmi_freeCallBack( RMAddress addr ); Use this function to free a callback allocated with dpmi_allocateCallBack(). Returns 1 on success, or 0 on failure. PMFarAddress DPMIFAR dpmi_getPMSaveStateProc(void); Use this function to obtain a protected mode function pointer which, when called, will save the protected mode state of the processor. On entry to the function, you need to set the registers to: ES:DI points to a protected mode buffer (ES:EDI for DPMI32). AL = 0 to save the state, or 1 to restore the state. Use dpmi_getSaveStateSize() to get the required size of the buffer. Returns the address of the function on success, or 0 on failure. RMAddress DPMIFAR dpmi_getRMSaveStateProc(void); Use this function to obtain a real mode function pointer which, when called, will save the real mode state of the processor. On entry to the function, you need to set the registers to: ES:DI points to a real mode buffer (ES:EDI for DPMI32). AL = 0 to save the state, or 1 to restore the state. Use dpmi_getSaveStateSize() to get the required size of the buffer. Returns the real mode address of the function on success, or 0 on failure. unsigned short DPMIFAR dpmi_getSaveStateSize(void); Use this function to obtain the size of the buffer required for a call to the Save State procedure(s) (see dpmi_getPMSaveStateProc() and dpmi_getRMSaveStateProc()). Note that a return value of 0 IS valid - it means that the DPMI host doesn't require that the state be saved. PMFarAddress DPMIFAR dpmi_getPMSwitchProc(void); Use this function to obtain a protected mode function pointer which, when called, will switch to real mode. Returns the function pointer on success, or 0 on failure. On entry to the function, the registers need to be: AX = new DS (RMSegment) CX = new ES (RMSegment) DX = new SS (RMSegment) BX = new SP (EBX = new ESP on DPMI32) SI = new CS (RMSegment) DI = new IP (EDI = new EIP on DPMI32) It is up to you to save the state before calling this function pointer (see dpmi_getPMSaveStateProc()). RMAddress DPMIFAR dpmi_getRMSwitchProc(void); Use this function to obtain a real mode function pointer which, when called, will switch to protected mode. Returns the function pointer on success, or 0 on failure. On entry to the function, the registers need to be: AX = new DS (PMSelector) CX = new ES (PMSelector) DX = new SS (PMSelector) BX = new SP (EBX = new ESP on DPMI32) SI = new CS (PMSelector) DI = new IP (EDI = new EIP on DPMI32) It is up to you to save the state before calling this function pointer (see dpmi_getRMSaveStateProc()). void DPMIFAR dpmi_getVersion( LPDPMIVersion ver ); Use this function to get version information for the DPMI host. Memory Management Services -------------------------- These functions perform actions on linear memory. int DPMIFAR dpmi_getMemInfo( LPDPMIMemInfo info ); Use this function to obtain "heap" information from the DPMI host. Returns 1 on success, or 0 on failure. PMHandle DPMIFAR dpmi_allocateLinearMem( unsigned long len, LinearAddress DPMIFAR*addr ); Use this function to allocate linear memory of length . If successful, returns a handle to the memory, and * is set to the linear address of the memory. On failure, returns 0. int DPMIFAR dpmi_freeLinearMem( PMHandle handle ); Use this function to free memory allocated with dpmi_allocateLinearMem(). Returns 1 on success, or 0 on failure. PMHandle DPMIFAR dpmi_reallocateLinearMem( PMHandle handle, unsigned long len, LPRMAddress addr ); Use this function to reallocate memory allocated with dpmi_allocateLinearMem() to bytes. On success, returns the new handle for the memory and * is set to the new linear address; on failure returns 0. Page Locking Services --------------------- Use these functions (cautiously) to effect page locking. int DPMIFAR dpmi_lockLinearMem( LinearAddress addr, unsigned long len ); Use this function to lock a linear memory range starting at and extending for bytes. Returns 1 on success, or 0 on failure. Note that in implementation, pages get locked, so that more than bytes might get locked if it straddles a page boundary. int DPMIFAR dpmi_unlockLinearMem( LinearAddress addr, unsigned long len ); Use this function to unlock memory locked with dpmi_lockLinearMem(). Returns 1 on success, or 0 on failure. int DPMIFAR dpmi_markRModePageable( RMAddress addr, unsigned long len ); Use this function to mark a section of real mode memory as pageable. Returns 1 on success, or 0 on failure. int DPMIFAR dpmi_relockRModeRegion( RMAddress addr, unsigned long len ); Use this function to lock a section of real mode memory that was marked as pageable with dpmi_markRModePageable(). Returns 1 on success, or 0 on failure. unsigned long DPMIFAR dpmi_getPageSize(); Use this function to obtain the number of bytes per page. Returns the value on success, or 0 on failure. Demand Paging Performance Tuning Services ----------------------------------------- These functions are used to mark memory as LRU (so its first to be paged out of memory), or to discard memory. Use with caution. int DPMIFAR dpmi_markLinearMem( LinearAddress addr, unsigned long len ); Use this function to mark a linear range as next to be paged. Returns 1 on success, or 0 on failure. int DPMIFAR dpmi_discardLinearMem( LinearAddress addr, unsigned long len ); Use this function to request that a linear range be discarded. Returns 1 on success, or 0 on failure. Physical Address Mapping ------------------------ This function (not always supported, unfortunately) is for mapping physical memory addresses to a linear address for use with other dpmi_xxxx() functions. Normally, this would be used with a peripheral that maps to a (high) physical memory address. LinearAddress DPMIFAR dpmi_mapPhysicalMem( LinearAddress addr, unsigned long len ); Use this function to map a physical memory range (above 1MB!) to a linear memory range that can be used with other dpmi_xxxx() functions. Returns the mapped linear address on success, or 0 on failure. Virtual Interrupt State Services -------------------------------- These functions effect the virtual interrupt table. int DPMIFAR dpmi_disableIntr(void); Use this function to disable interrupts. Returns 1 if interrupts were previously enabled, or 0 if they were disabled. int DPMIFAR dpmi_enableIntr(void); Use this function to enable interrupts. Returns 1 if interrupts were previously enabled, or 0 if they were disabled. int DPMIFAR dpmi_getIntr(void); Use this function to get the virtual interrupt state. Returns 1 if interrupts are enabled, or 0 if they are disabled. Debug Register Support ---------------------- These function allow rudimentary debugging capabilities. WatchPoint DPMIFAR dpmi_setWatchPoint( LinearAddress addr, int nrBytes, int type ); Use this function to set a watch point on a byte, word, or double word in linear address space. is the linear address of the memory, is 1 (a byte), 2 (a word), or 4 (a double word), and is the type of watch point to apply (must be one of watchpoint_types). Returns the watch point "handle" on success, or 0 on failure. int DPMIFAR dpmi_clearWatchPoint( WatchPoint ); Use this function to "clear" a watch point that was applied with the dpmi_setWatchPoint() function. Returns 1 on success, or 0 on failure. int DPMIFAR dpmi_watchPointExecuted( WatchPoint ); Use this function to test if a watch point was executed (read, written, etc). Returns 1 if the watch point was executed, or 0 on failure or if the watch point was not executed. int DPMIFAR dpmi_resetWatchPoint( WatchPoint ); Use this function to reset a watch point so you can again test for when it becomes executed. Returns 1 on success, or 0 on failure. Goodies ------- Currently, these functions are just DMI32-only functions that will read and write to a PMFarAddress (or selector+offset combination) in the same manner as a _fmemcpy() function call. You must be compiling for DPMI32 for these functions to be defined, and they are only present in DPMIC32.LIB. void copy32( PMFarAddress dest, PMFarAddress source, unsigned long len ); Use this function to write bytes from source to dest. void copy32aux( unsigned long destOfs, PMSelector destSel, unsigned long srcOfs, PMSelector srcSel, unsigned long len ); Use this function to write bytes from srcSel:srcOfs to destSel:destOfs, where srcSel and destSel are protected mode selectors, and srcOfs and destOfs are 32-bit offsets into those selectors.